home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-01
/
kvbugs.zip
/
TVBUG-KV.TXT
< prev
Wrap
Text File
|
1992-10-29
|
22KB
|
735 lines
TurboVision Bug Listing 10/29/92
The following is an *informal* bug list for Borland C++ / TurboVision.
The list is maintained strictly as a service to other forum members;
I do not receive any compensation for this. All information is
supplied on an "as-is" basis -- I make no guarantees that the problems
or solutions are accurate.
Wherever possible, I have checked whether or not the bugs still exist
in Borland C++ 3.1 (I never remember the A/F version numbers).
When I refer a bug being demonstrated or
confirmed by someone, I mean simply that I read their forum message to
that effect. I apologize in advance if I have misread or misquoted
anyone.
The list contains bugs that I have found while perusing the forum,
and is somewhat slanted to TurboVision and C++ (I don't use OWL or
Templates yet, so I haven't been paying attention to them as much). If
you send me bugs in these areas, I will add them to the list.
If you have any corrections or additions to this list, please send
them to me and I will add them to the list. Hope this list helps.
-- Ken Vogel 74007,564 --
------------------------------------------------------------------
Id: KV-1
Location: TurboVision
Problem: Unfreed memory when TStreamable descendent object pointers
are written to an ofpstream.
Version: Exists in BC 3.0
Appears to be fixed in 3.1 (although I have not tested memory
counters to verify that there is no leak, as Borland made other
changes to this file as well)
Proposed Solution: The objs member of ofpstream contains pointers to
TPWObj elements, which are created while the stream is written. However,
when the stream is deleted, the TV code sets the shouldDelete member of
objs to False, preventing the TPWObj members from being properly deleted.
**** TOBJSTRM.CPP Line 99
==== OLD ====
TStreamableTypes::~TStreamableTypes()
{
shouldDelete = False;
}
===== NEW ====
TStreamableTypes::~TStreamableTypes()
{
}
**** TOBJSTRM.CPP Line 512
==== OLD ====
opstream::~opstream()
{
objs->shouldDelete = False;
objs->shutDown();
delete objs;
}
===== NEW ====
opstream::~opstream()
{
objs->destroy (objs);
}
*** END ***
------------------------------------------------------------------
Id: KV-2
Location: TurboVision
Problem: TFileDialog does not correctly read subdirectories.
Version: Exists in BC 3.0, fixed in 3.1
Proposed Solution: A call to fnmerge incorrectly uses *.* as the
extension when building the directory mask. In BC 3.0, the fnmerge
no longer accepts this.
**** TFILLIST.CPP Line 170
==== OLD ====
fnmerge( path, drive, dir, file, "*.*" );
===== NEW ====
fnmerge( path, drive, dir, "*", ".*" );
------------------------------------------------------------------
Id: KV-3
Location: TurboVision
Problem: TGroup::valid is not re-entrant. If you have multiple windows
on your desktop, and wish to display a message during your
valid method in one of the windows, other windows will receive
an incorrect command parameter to their valid.
Version: Exists in BC 3.0, and in 3.1
Proposed Solution:
TGROUP uses a global static variable to pass the current
command to the iterator function isInvalid. Pass this parameter
via a pointer instead.
**** TGROUP.CPP Line 503
==== OLD ====
static ushort cmd;
Boolean isInvalid( TView *p, void * )
{
return Boolean( !p->valid( cmd ) );
}
Boolean TGroup::valid( ushort command )
{
cmd = command;
return Boolean( firstThat( isInvalid, 0 ) == 0 );
}
===== NEW ====
Boolean isInvalid( TView *p, void *commandP )
{
return Boolean( !p->valid( *(ushort *)commandP ) );
}
Boolean TGroup::valid( ushort command )
{
return Boolean( firstThat( isInvalid, &command ) == 0 );
}
------------------------------------------------------------------
Id: KV-4
Location: TurboVision
Problem: Writing duplicate pointers to descendants of TStreamable
streams may writes out a new copy of the pointed to objects
each time. Occurs only if pointers to two or more different
classes are written to a stream.
Version: Exists in BC 3.0, fixed in 3.1
Proposed Solution:
The list of pointers which have been written to the stream is
maintained in a descendent of TNSSortedCollection by ofpstream.
This descendent incorrectly performs a pointer comparison when
searching to see if a pointer has already been written to the
stream. In some conditions, this causes the search to terminate
before the pointer is found, thus causing the same object to
be written twice.
**** TOBJSTRM.CPP Line 123
==== OLD ====
int TPWrittenObjects::compare( void *o1, void *o2 )
{
if( o1 == o2 )
return 0;
else if( o1 < o2 )
return -1;
else
return 1;
}
===== NEW ====
int TPWrittenObjects::compare( void *o1, void *o2 )
{
if( o1 == o2 )
return 0;
else if( (long)o1 < (long)o2 )
return -1;
else
return 1;
}
------------------------------------------------------------------
Id: KV-5
Location: TurboVision
Problem: Directories with names less than two characters in length
are not displayed in a TFileList (or TFileDialog)
Version: Exists in BC 3.0, and in 3.1
Proposed Solution: For some reason, TFileList elimates directories
whose length is less than or equal to four.
**** TFILLIST.CPP Line 187
==== OLD ====
if( strlen( dir ) > 4 )
{
===== NEW ====
if( strlen( dir ) > 1 )
{
------------------------------------------------------------------
Id: KV-6
Location: Compiler optimization
Problem: (Sorry, I don't have the name of the person who originated this
message. Thanks, whoever you are. --KV--)
Version: Exists in BC 3.0. Seems to be fixed in 3.1
This code demonstrates the problem (with loop optimizer ON)
int main()
{
for( int i = 10; i>=0; i--)
cout << (10-i) << '\n';
return 0;
}
The program output should be "0,1,2,...,10".
Instead, the output is "0,-1,-2,...,-10".
The bug is in the loop optimizer. The compiler introduces an
induction variable to replace the expression (10-i),
which it stores in register DI. The compiler correctly
initializes DI to 0, but in the iteration step it *decrements*
DI when it should *increment* it. Looks like you tripped over
the "double negative."
Proposed Solution: Don't make this code construct, or turn off loop
optimization for those sections of the code which use constructs
similar to this one.
------------------------------------------------------------------
Id: KV-7
Location: Compiler Optimization
Version: Exists in BC 3.0. I haven't tested 3.1
Problem: The -Ob (dead code) optimization and multiple floating
point assignments causes valid store to be eliminated.
Example:
a = b = 3.0;
If a was not used, the store to b would also be
eliminated
Relayed in a message from Jeff Stock, originally posted by
Mel Corey.
Proposed Solution:
Disable -Ob for dead assignments, eliminate unused variables,
or store unused variables separately.
------------------------------------------------------------------
Id: KV-8
Location: Compiler
Version: Exists in BC 3.0. I haven't tested 3.1
Problem: A for loop with a constant test expression that evaluates
to 0 has its body executed once. (I'm not sure if this is
related to any optimizations).
Example:
for( ;0; ) { /*this executes once*/ }
I took this from a message by Mark Sidell.
Proposed Solution:
Eliminate the loop, or use a variable in the condition.
------------------------------------------------------------------
Id: KV-9
Location: C++ Compiler
Version: Exists in BC 3.0. Fixed in 3.1
Problem: Temporary destructor is not called in certain situations. Thanks
to a forum message by Mark Sidell for this example (confirmed by
Eric Nagler).
The following program demonstrates what appears to be a bug in BCC 3.0.
The Der ctor creates a temporary Item and passes its address
to the base ctor. But, the temporary Item is never destroyed!
#include <iostream.h>
struct Item {
Item() { cout << "Item ctor\n"; }
~Item() { cout << "Item dtor\n"; }
};
struct Base {
Base( Item *) {}
};
struct Der : Base {
// Yikes! The temporary Item is never destroyed.
Der() : Base( &Item()) {}
};
int main()
{
Der oDer;
return 0;
}
------------------------------------------------------------------
Id: KV-10
Location: VROOMing TurboVision programs (and potentially others)
Version: Exists in BC 3.0 and in 3.1
Problem: The linker warning:
No stub for fixup at _DATA:xxxx in module yyyy.CPP
Is reported for certain VROOMed modules. These modules do
not execute correctly.
Proposed Solution:
The problem seems to be related to incorrect code produced
for certain virtual tables. Only modules which inherit certain
classes or constructors develop the problem.
The solution (taken from the TurboVision make file) is to compile
these modules with the -B and -Vs options (compile via assembly
and local virtual tables). Note that this requires more memory,
and may not be possible in the IDE, thus forcing you to a make
file. Personally, I don't VROOM these modules until I'm ready
for a release, when I do it with a make file.
However, if you have enough modules, you will notice that you
still get the 'No stub' error even though you compiled it -Vs -B.
First, try it *without* the -Vs -B (still overlaid). Oddly enough,
some modules work this way.
Unfortunately, some modules don't work in either compilation
option. Your only option (as far as I know) is to leave those
ones non-overlaid. If you find a way to overlay all modules,
**please send me mail**. It would really be a big help to me.
------------------------------------------------------------------
Id: KV-11
Location: Compiler
Version: Exists in BC 3.0. Fixed in 3.1
Problem: The compiler generates bad code for 1, 2 and 4 byte array
initializers. Thanks to TechMate, Inc. for the following
simple example (I took it from one of their forum msgs). Jeff
Stock of Borland confirmed that it was a problem.
#pragma inline
void main()
{
char x[4] = "bug";
};
When compiled with the following command line:
bcc -ml x.cpp
It generates assembly code with this error:
Assembling file: x.ASM
**Error** x.ASM(45) Too few operands to instruction
Error messages: 1
Warning messages: None
Passes: 1
Remaining memory: 378k
Proposed Solution:
Don't use 1, 2 or 4 byte arrays (use other sizes)?
------------------------------------------------------------------
Id: KV-12
Location: Compiler
Version: Exists in BC 3.0. Fixed in 3.1
Problem: Certain shifting operations do not perform correctly with
jump optimization.
Example:
#include <stdio.h>
long Fct (void)
{
int a, b;
a = 1;
b = 0;
// try this with and without jump optimization
return (((long)a) | (((long)b)<<16));
}
main ()
{
long l, Ref;
Ref = Fct ();
l = ((long)1)<<16;
printf ("Long: %lX\n", l);
printf ("Return: %lX\n", Ref);
return 0;
}
This was confirmed by Jeff Stock at Borland.
Proposed Solution:
Turn off jump optimization for those modules that use shifting
similar to that shown above.
------------------------------------------------------------------
Id: KV-13
Location: TV
Version: Exists in BC 3.0 and in 3.1 (although TOBJSTRM has changed
in 3.1, so my original line numbers don't quite work).
Problem: The TurboVision stream manager (contained in TOBJSTRM)
is very unstable if the file you read is corrupted for any
reason. There are several calls to assert(), which does
not uninstall the mouse interrupt when exiting, as well as
some possible null pointer writing if there are problems.
Also, If you try to read an object whose class is not registered
with the stream manager (or a corrupt file), this crashes
your application.
Proposed Solution:
I have modified TOBJSTRM to set the stream error flag when
an error occurs. The first step is to replace
all occurances of assert() with the following two macros:
** START **
#define fassert(Condition) if (!(Condition)) \
{ setstate(ios::badbit); errno = EINVDAT; }
#define foassert(Condition,Obj) if (!(Condition)) \
{ (Obj).setstate(ios::badbit); errno = EINVDAT; }
** END **
Next, you should add some additional tests. In particular, the
two calls to ipstream::readPrefix, which returns a pointer, do
not check if this pointer is NULL (object not found). Change
these lines to read something like:
**** FROM ****
const TStreamableClass *pc = ps.readPrefix();
ps.readData( pc, &t );
ps.readSuffix();
** END **
***** TO ******
const TStreamableClass *pc = ps.readPrefix();
foassert (pc != 0, ps);
if (pc != 0)
{
ps.readData( pc, &t );
ps.readSuffix();
}
** END **
Also, add the following to the start of BOTH versions of
ipstream::readString:
** START **
if (!good())
return 0;
** END **
Add the following to the start of ipstream& operator >>
for TStreamable&:
** START **
if (!ps.good())
return ps;
** END **
Add the following to the start of ipstream& operator >> for
void *&:
** START **
if (!ps.good())
{
t = 0;
return ps;
}
** END **
I'm sure there are more areas, but these have served me well.
------------------------------------------------------------------
Id: KV-14
Location: TV
Version: Exists in BC 3.0. Appears fixed 3.1
Problem: Your application will crash with an abnormal program termination
if you try to do a file dialog in a directory with too many
files.
Proposed Solution:
Interestingly enough, TFILLIST has code to handle too many
files. The loop to read a file diligently checks if the
pointer (allocated via new) is NULL, and will terminate the
loop. However, NEW.CPP provided with TurboVision will
*terminate* when no more memory is available (after dipping
into the safety pool). TFILLIST should check the Safety Pool
(via lowMemory) while it is looping, NOT the pointer itself.
In TFileList::readDirectory, change lines 167 and 179 as follows:
**** FROM *****
while( p != 0 && res == 0)
***** TO *****
while( p != 0 && res == 0 && !lowMemory())
***** END *****
Also, change line 214:
**** FROM *****
if( p == 0 )
messageBox( tooManyFiles, mfOKButton | mfWarning );
***** TO *****
if( p == 0 || lowMemory())
messageBox( tooManyFiles, mfOKButton | mfWarning );
***** END *****
------------------------------------------------------------------
Id: KV-15
Location: TV
Version: Exists in BC 3.0. Appears to still exist in 3.1 (although
they fixed some other problems there)
Problem:
A descendent of TNSCollection which sets the shouldDelete
member to false will leave one unfreed pointer if it is
destroyed when items are contained within it.
The TOBJSTRM module creates just such a collection during
a read of a stream containing TStreamable *.
Proposed Solution:
The problem appears to be as follows. The shutDown function
of TNSCollection calls the member function setLimit(0) to
free all object pointers. setLimit *never* lets limit fall
below count. Thus, if you destroy a TNSCollection with
count > 0, the items member of TNSCollection will never be
freed. (Note that I'm not talking about the contained pointers,
which are obviously the responsibility of the caller in a
shouldDelete = False situation).
To fix the problem, change line 57 of TCOLLECT.CPP:
**** FROM *****
void TNSCollection::shutDown()
{
if( shouldDelete )
freeAll();
setLimit(0);
TObject::shutDown();
}
***** TO *****
void TNSCollection::shutDown()
{
if( shouldDelete )
freeAll();
else
count = 0;
setLimit(0);
TObject::shutDown();
}
***** END *****
------------------------------------------------------------------
Id: KV-16
Location: TV
Version: Exists in BC 3.0. Appears to still exist in 3.1 (although
they fixed some other problems there)
Problem:
Typing too many characters into the input line of a file dialog
will crash the program.
Proposed Solution:
The problem arises when you call getFileName with a string of
size MAXPATH. TFILDLG has a line that can cause the
resultant path to be approximately 2 * MAXPATH.
To avoid the problem, you can either pass a string of
size MAXPATH * 2 into getFileName, OR make the following 2 changes
to TFILDLG:
**** FROM (Circa line 178) *****
static void trim( char *dest, const char *src )
{
while( *src != EOS && isspace( *src ) )
src++;
while( *src != EOS && !isspace( *src ) )
*dest++ = *src++;
*dest = EOS;
}
***** TO *****
static void trim( char *dest, const char *src, int size )
{
while( *src != EOS && isspace( *src ) )
src++;
while( *src != EOS && !isspace( *src ) && --size > 0)
*dest++ = *src++;
*dest = EOS;
}
**** FROM (Circa line 196) *****
trim( s, fileName->data );
if( relativePath( s ) == True )
{
strcpy( s, directory );
trim( s + strlen(s), fileName->data );
}
***** TO *****
trim( s, fileName->data, MAXPATH - 1 );
if( relativePath( s ) == True )
{
strcpy( s, directory );
trim( s + strlen(s), fileName->data, MAXPATH - 1 - strlen (s) );
}
***** END ****
------------------------------------------------------------------
Id: KV-17
Location: TV (with VROOM)
Version: Exists in BC 3.0. Appears to still exist in 3.1
Problem:
A VROOM'ed TurboVision application has a very subtle problem which can
cause very rare program crashes.
Proposed Solution:
The problem occurs TEVENT.CPP is compiled with overlays off and
standard stack frame off. TEventQueue::suspend (a very short
function) compiles into single call to THWMouse::suspend (a VROOMed
module, by default) without the standard stack frame.
If the overlay manager is invoked when THWMouse is called, it may
lose the correct return address to the caller of TEventQueue::suspend
(TProgram::suspend). This causes a program crash.
The solution is to compile TEVENT.CPP with standard stack frame (-k)
Change MAKEFILE in the TVISION\SOURCE directory as follows:
**** FROM (Line 218) *****
tevent.obj : tevent.cpp
$(BCC) -Y- $&.cpp
***** TO *****
tevent.obj : tevent.cpp
$(BCC) -Y- -k $&.cpp
***** END ****
------------------------------------------------------------------
Id: KV-18
Location: TV (with VROOM)
Version: Exists in BC 3.0. Appears to still exist in 3.1
Problem:
A VROOM'ed TurboVision application crashes when you get a critical error.
Proposed Solution:
The basic problem is that you must make sure that the overlay manager
CANNOT be called in a critical error handler (it uses those hi-numbered
DOS function calls). The powers that be at Borland correctly remove
SYSERR.CPP and SYSINT.CPP from the overlay list. However, SYSERR.CPP
calls the following modules, which must also be removed from the list:
tscreen
drivers
swapst
tevent
The solution is to compile these modules separately in the TV makefile,
and include them NON-overlayed in your program. I create a library with
the six non-overlayed files. Creating the library also avoids BC 3.0
nasty habit of relinking every time you run because it can't find the
source for the .OBJ files.
------------------------------------------------------------------
Id: KV-19
Location: TV
Version: Exists in BC 3.0. Appears to still exist in 3.1
Problem:
The critical error handler crashes if it receives errors which are
greater than 14 (i.e., it happens on a network, etc.).
Proposed Solution:
The problem lies in SYSERR.CPP, which blindly assumes that all errors
are less than 14 when it indexes its error name array. Simply put
a check for the index in the code.
To fix the problem, change line 122 of TCOLLECT.CPP:
**** FROM *****
sprintf( s, errorString[ errorCode ], drive + 'a' );
***** TO *****
if (errorCode < sizeof (errorString) / sizeof (*errorString))
sprintf( s, errorString[ errorCode ], drive + 'a' );
else
sprintf( s, "Critical error %d", errorCode);
***** END *****